package com.cainli.image;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

import org.apache.http.Header;
import org.apache.http.client.CookieStore;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicHeader;

import com.cainli.task.Task;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.view.animation.AnimationUtils;


public class URLDrawable extends Drawable implements Drawable.Callback, Runnable
{
    private static final String TAG = "URLDrawable";
    private static final String CACHE_PREFIX = "Cache_";
    /**
     * 状态, 正在加载
     */
    public static final int LOADING = 0;
    /**
     * 状态, 加载成功
     */
    public static final int SUCCESSED = 1;
    /**
     * 状态, 加载失败
     */
    public static final int FAILED = 2;
    /**
     * 状态, 加载取消
     */
    public static final int CANCLED = 3;
    
    // 渐现动画的持续时间
    private int ANIMATION_DURATION = 600;

    /**
     * 默认参数(全局)
     */
    static URLDrawableParams sDefaultDrawableParms;    
    
    /**
     * 内存缓存,
     * value中第一个值为ConstantState, 第二个值为缓存所占的内存(长x宽x像素所占字节)
     */
    private static MemoryCache sMemoryCache;
    
    /**
     * 文件缓存
     */
    private static DiskLruCache sDiskCache;
    /**
     * 创建缓存时, 使用的锁
     */
    private static final Object sDiskCacheLock = new Object();
    /**
     * DiskCache是否在初始化中.
     */
    private static boolean sDiskCacheStarting = true;
    
    public static final int DISK_CACHE_INDEX = 0;
    
    /**
     * density
     */
    private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
    

//    /**
//     * HttpClient(单例)
//     */
//    private static DefaultHttpClient sHttpClient = createHttpClient();
    
    // 配置属性..
    /**
     * 缓存文件
     */
    private File mCacheFile;

    /**
     * 加载成功后, 是否以fade-in方式显示图片
     */
    boolean mFadeInImage;

    /**
     * 是否播放gif动画
     */
    private boolean mUseGifAnimation;

    private Drawable mLoadingDrawable;

    private Drawable mFailedDrawable;

    // headers
    private Header[] mHeaders;

    // cookies
    private CookieStore mCookies;

//    // 缓存文件名
//    private String mCacheName;

    // 状态属性
    /**
     * 当前使用的Drawable
     */
    private Drawable mCurrDrawable;

    // ConstantState,用来重复创建图片
    protected URLState mDrawableContainerState;

    // 是否已经开始读图片
    private boolean isLoadingStarted = false;
    // 是否读完图片
//    private boolean isLoadingFinished = false;
    
    // 渐现动画是否启动
    private boolean mFadeInAnimationStarted = false;
    // 渐现动画起始时间
    private long mFadeInAnimationStartTime = -1;

    /**
     * 当前状态
     */
    private int mStatus = LOADING;
    
    /**
     * 是否自动加载
     */
    private boolean mAutoDownload = true;

    // 本身的属性
    private int mAlpha = 0xFF;
    private ColorFilter mColorFilter;
    private boolean mMutated;
    private URLDrawableListener mListener;

    private int mReqWidth;
    private int mReqHeight;
    
    /**
     * 缓存消息的容量, 暂定为100
     */
    private static final int PENDING_ACTION_CAPACITY = 100;
    
    /**
     * 暂停标记
     */
    private static boolean sPause = false;
    /**
     * 暂停的同步锁
     */
    private static Object sPauseLock = new Object();
    
    /**
     * tag..
     */
    private Object mTag;
    
    /**
     * 点击的颜色
     */
    private int mFliterColor = 0;
    
//    private boolean hasCallback = false;
    
    /**
     * 暂停恢复后, 用来还原消息, 有容量限制
     */
    private static final ArrayList<WeakReference<URLDrawable>> sPendingActions = new ArrayList<WeakReference<URLDrawable>>(PENDING_ACTION_CAPACITY + 5){
        
        public boolean add(WeakReference<URLDrawable> object) {
            boolean ret = super.add(object);
            ensureCapacity();
            return ret;
        };
        
        private void ensureCapacity()
        {
            int size = size();
            if(size > PENDING_ACTION_CAPACITY)
            {
                removeRange(0, size - PENDING_ACTION_CAPACITY - 1);
            }
        }
    };
    
    @Override
    public int getChangingConfigurations()
    {
        return super.getChangingConfigurations() | mDrawableContainerState.mChangingConfigurations;
    }

    @Override
    public boolean getPadding(Rect padding)
    {
        if (mCurrDrawable != null)
        {
            return mCurrDrawable.getPadding(padding);
        }
        else
        {
            return super.getPadding(padding);
        }
    }

    @Override
    public void setAlpha(int alpha)
    {
        if (mAlpha != alpha)
        {
            mAlpha = alpha;
            if (mCurrDrawable != null)
            {
                mCurrDrawable.setAlpha(alpha);
            }
        }
    }

    @Override
    public void setDither(boolean dither)
    {
        if (mDrawableContainerState.mDither != dither)
        {
            mDrawableContainerState.mDither = dither;
            if (mCurrDrawable != null)
            {
                mCurrDrawable.setDither(mDrawableContainerState.mDither);
            }
        }
    }

    @Override
    public void setColorFilter(ColorFilter cf)
    {
        if (mColorFilter != cf)
        {
            mColorFilter = cf;
            if (mCurrDrawable != null)
            {
                mCurrDrawable.setColorFilter(cf);
            }
        }
    }

    @Override
    protected void onBoundsChange(Rect bounds)
    {
        if (mCurrDrawable != null)
        {
            mCurrDrawable.setBounds(bounds);
        }
    }

    @Override
    public boolean isStateful()
    {
        return mDrawableContainerState.isStateful();
    }

    @Override
    protected boolean onStateChange(int[] states)
    {
        if (mCurrDrawable != null)
        {
            mCurrDrawable.setState(states);
            // 有设置点击色
            if(mFliterColor != 0)
            {
                for (int state : states)
                {
                    if(state == android.R.attr.state_pressed)
                    {
                        mCurrDrawable.setColorFilter(mFliterColor, PorterDuff.Mode.SRC_ATOP);
                        return true;
                    }
                }
                mCurrDrawable.setColorFilter(null);
            }
        }
        return true;
    }
    
    public void setClickFliterColor(int color)
    {
        this.mFliterColor = color;
    }

    @Override
    protected boolean onLevelChange(int level)
    {
        if (mCurrDrawable != null)
        {
            return mCurrDrawable.setLevel(level);
        }
        return false;
    }

    @Override
    public int getIntrinsicWidth()
    {
        return mCurrDrawable != null ? mCurrDrawable.getIntrinsicWidth() : -1;
    }

    @Override
    public int getIntrinsicHeight()
    {
        return mCurrDrawable != null ? mCurrDrawable.getIntrinsicHeight() : -1;
    }

    @Override
    public int getMinimumWidth()
    {
        return mCurrDrawable != null ? mCurrDrawable.getMinimumWidth() : 0;
    }

    @Override
    public int getMinimumHeight()
    {
        return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0;
    }

    @Override
    public boolean setVisible(boolean visible, boolean restart)
    {
        boolean changed = super.setVisible(visible, restart);
        if (mCurrDrawable != null)
        {
            mCurrDrawable.setVisible(visible, restart);
        }
        return changed;
    }

    @Override
    public int getOpacity()
    {
        return mCurrDrawable == null || !mCurrDrawable.isVisible() ? PixelFormat.TRANSPARENT : mDrawableContainerState
                .getOpacity();
    }

    @Override
    public ConstantState getConstantState()
    {
        if (mDrawableContainerState.canConstantState())
        {
            mDrawableContainerState.mChangingConfigurations = super.getChangingConfigurations();
            return mDrawableContainerState;
        }
        return null;
    }

    @Override
    public Drawable mutate()
    {
        if (!mMutated && super.mutate() == this)
        {
            if (mStatus != SUCCESSED)
            {
                mCurrDrawable.mutate();
            }
            mMutated = true;
        }
        return this;
    }

    @Override
    public void invalidateDrawable(Drawable who)
    {
        this.invalidateSelf();
    }

    @Override
    public void scheduleDrawable(Drawable who, Runnable what, long when)
    {
        scheduleSelf(what, when);
    }

    @Override
    public void unscheduleDrawable(Drawable who, Runnable what)
    {
        unscheduleSelf(what);
    }

    @Override
    public void draw(Canvas canvas)
    {
        if (mCurrDrawable != null)
        {
            int count = canvas.save();
            if(mFadeInImage && mFadeInAnimationStarted)
            {
                long currentTime = AnimationUtils.currentAnimationTimeMillis();
                if(mFadeInAnimationStartTime == -1)
                {
                    mFadeInAnimationStartTime = currentTime;
                }
                float normalizedTime = ((float) (currentTime - mFadeInAnimationStartTime)) / (float) ANIMATION_DURATION;
                if(normalizedTime >= 0.0f && normalizedTime <= 1.0f)
                {
                    final float interpolatedTime = (float) (1.0f - (1.0f - normalizedTime) * (1.0f - normalizedTime));
                    int multipliedAlpha = (int) (255 * interpolatedTime);
                    multipliedAlpha = Math.min(multipliedAlpha, 255);
                    Rect bounds = getBounds();
                    canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.width(), bounds.height(), multipliedAlpha,
                            Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
                    invalidateSelf();
                }
                else
                {
                    // 终止动画
                    mFadeInAnimationStarted = false;
                }
            }
            mCurrDrawable.draw(canvas);
            canvas.restoreToCount(count);
        }
        // 如果未开始，启动线程下载图片
        if(mAutoDownload)
        {
            if(!sPause)
            {
                startDownload();
            }
            // 暂停了, 加到pendingActions中, 等恢复后再开
            else
            {
                sPendingActions.add(new WeakReference<URLDrawable>(this));
            }
        }
    }
    
    /**
     * 开始下载
     */
    public void startDownload()
    {
        // 如果加载已开始, 再调也没用了
        if(!isLoadingStarted)
        {
            // 别的drawable已经将其加载完毕
            if(mDrawableContainerState.mSuccessed != null)
            {
                this.mCurrDrawable = mDrawableContainerState.mSuccessed.newDrawable();
                isLoadingStarted = true;
                invalidateSelf();
            }
            else
            {
                isLoadingStarted = true;
                ProtocolDownloader downloader = sDefaultDrawableParms.mDownLoaderMap.get(getURL().getProtocol());
                if(!downloader.onPreDownload(this))
                {
                    executeDownloadTask();
                }
            }
        }
    }
    
    /**
     * 通知图片已脏, 会重新调用startDownload
     */
    public void invalidate()
    {
        isLoadingStarted = false;
        invalidateSelf();
    }
    
    @Override
    public void run()
    {
        startDownload();
    }
    
    /**
     * 设置targetDensity, 默认为根据设备的density进行缩放,
     * 如果不想进行缩放, 可以调用setTargetDensity(DisplayMetrics.DENSITY_DEFAULT)
     * @param mTargetDensity
     */
    public void setTargetDensity(int density)
    {
        if(density != this.mTargetDensity)
        {
            this.mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
            // 如果加载完成, 更新successed drawable..
            if(mStatus == SUCCESSED)
            {
                if(mCurrDrawable instanceof BitmapDrawable)
                {
                    ((BitmapDrawable)mCurrDrawable).setTargetDensity(density);
                }
                else if(mCurrDrawable instanceof GifDrawable)
                {
                    ((GifDrawable) mCurrDrawable).setTargetDensity(density);
                }
            }
        }
    }
    
    /**
     * 设置是否自动下载, 如果设置为false, 则必须调用startDownload才会下载
     * @param autoDownload
     */
    public void setAutoDownload(boolean autoDownload)
    {
        this.mAutoDownload = autoDownload;
        if(autoDownload)
        {
            invalidateSelf();
        }
    }
    
    public URL getURL()
    {
        return mDrawableContainerState.mUrl;
    }
    
    /**
     * 获取状态
     * @return
     */
    public int getStatus()
    {
        return mStatus;
    }

    /**
     * 根据设置, 生成task并启动
     */
    private void executeDownloadTask()
    {
        // asyctask
        if(sDefaultDrawableParms.mTaskType == URLDrawableParams.TASK_TYPE_ASYNC_TASK)
        {
            new DownloadAsyncTask().execute(getURL());
        }
        // SwingWorker
        else 
        {
            new DownloadTask().execute();
        }
    }
    
    /**
     * 在当前线程立刻下载, 需要谨慎使用.
     * 一般用于预加载 
     * <b>不要在main线程调用.</b>
     * <b>不能把drawable设置在View上</b>
     */
    public void downloadImediatly()
    {
        try
        {
            isLoadingStarted = true;
            Object res = loadImage(getURL(), false);
            onLoadSuccessed(res);
        }
        catch (Exception e)
        {
            onLoadFailed(e);
        }
    }
    
    private class DownloadTask extends Task<Object, Integer>
    {

        public DownloadTask()
        {
            super(null);
        }

        @Override
        protected Object doInBackground() throws Exception
        {
            return loadImage(getURL(), isCancelled());
        }
        
        @Override
        protected void succeeded(Object result)
        {
            onLoadSuccessed(result);
        }
        
        @Override
        protected void failed(Throwable cause)
        {
            onLoadFailed(cause);
        }
        
        @Override
        protected void cancelled()
        {
            onLoadCanceled();
        }
    }
    
    private class DownloadAsyncTask extends AsyncTask<URL, Integer, Object>
    {

        @Override
        protected Object doInBackground(URL... url)
        {
            try
            {
                return loadImage(url[0], isCancelled());
            }
            catch (Throwable e)
            {
                return e;
            }
        }
        
        @Override
        protected void onPostExecute(Object result)
        {
            if(result instanceof Throwable)
            {
                onLoadFailed((Throwable) result);
            }
            else
            {
                onLoadSuccessed(result);
            }
        }
        
        @Override
        protected void onCancelled()
        {
            onLoadCanceled();
        }
    }
    
    private Object loadImage(URL url, boolean isCanceled) throws Exception
    {
        Object result = null;
        
        File cacheFile = mCacheFile;
        // 缓存key
        final String cacheKey;
        
        pauseThread();
        
        ProtocolDownloader downloader = sDefaultDrawableParms.mDownLoaderMap.get(url.getProtocol());
        // 没有设置缓存文件, 使用默认下载
        if(cacheFile == null)
        {
            cacheKey = hashKeyForDisk();
            // 从本地缓存读取
            result = getImageFromDiskLruCache(cacheKey, downloader);
            
            // 读取失败, 启动下载, 并从下载后的文件中读取
            if(result == null)
            {
                if(sDiskCache != null)
                {
                    result = downloadImageToDiskLruCache(url, cacheKey, downloader);
                }
                else
                {
                    // TODO 如果不存在sDiskCache(一般是sd空间不足, 或者缓存文件夹不存在, 如sd卡拔出之类)
                    result = decodeImageFromURL(url, downloader);
                }
            }            
        }
        // 手动设置了缓存文件
        else
        {
            // 从本地缓存读取
            result = decodeFile(cacheFile, downloader);
            
            // Step 3. 读取失败, 启动下载
            if(result == null)
            {
                result = downloadImageToFile(url, cacheFile, downloader);
            }
        }        
        
        pauseThread();
        
        return result;
    }

    private void pauseThread()
    {
        // 暂停中, 停掉线程
        synchronized (sPauseLock)
        {
            while (sPause)
            {
                try
                {
                    sPauseLock.wait();
                }
                catch (InterruptedException e)
                {
                }
            }
        }
    }

    /**
     * 
     * @param url
     * @param downloader 
     * @return
     */
    private Object decodeImageFromURL(URL url, ProtocolDownloader downloader)
    {
        return null;
    }

    /**
     * 下载图片到文件里
     * @param url
     * @param result
     * @param cacheFile
     * @param downloader 
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     */
    private Object downloadImageToFile(URL url, File cacheFile, ProtocolDownloader downloader) throws FileNotFoundException,
            IOException
    {
        Object result = null;
//        ProtocolDownloader downloader = sDefaultDrawableParms.mDownLoaderMap.get(url.getProtocol());
        if(downloader != null)
        {
            // 使用disk cache
            if(downloader.useDiskCache())
            {
                OutputStream out = null;
                try
                {
                    out = new FileOutputStream(cacheFile);
                    cacheFile = downloader.downloadImage(url, out, mHeaders, mCookies);
                }
                finally
                {
                    try
                    {
                        if (out != null)
                        {
                            out.close();
                        }
                    }
                    catch (IOException e){}
                }
            }
            else
            {
                result = decodeFile(downloader.downloadImage(url, null, mHeaders, mCookies), downloader);
            }
        }
        return result;
    }

    
    
    /**
     * 加载成功
     * @param image
     */
    protected void onLoadSuccessed(Object image)
    {
        if(image instanceof Bitmap)
        {
            // 如果启动
            if (isLoadingStarted)
            {
                Drawable oldDrawable = mCurrDrawable;
                BitmapDrawable bitmapDrawable = new BitmapDrawable(null, (Bitmap) image);
//                bitmapDrawable.setTargetDensity(mDrawableContainerState.density);
                // 3.0的bug, 如果alpha为255的话, 透明色会变成黑色
//                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
//                        && bitmapDrawable.getOpacity() != PixelFormat.OPAQUE
//                        && mAlpha >= 0xff)
//                {
//                    bitmapDrawable.setAlpha(254);
//                }
//                else
                {
                    bitmapDrawable.setAlpha(mAlpha);
                }
                bitmapDrawable.setVisible(isVisible(), true);
                bitmapDrawable.setDither(mDrawableContainerState.mDither);
                bitmapDrawable.setColorFilter(mColorFilter);
                bitmapDrawable.setState(URLDrawable.this.getState());
                bitmapDrawable.setLevel(getLevel());
                bitmapDrawable.setCallback(URLDrawable.this);
                bitmapDrawable.setTargetDensity(mTargetDensity);
                bitmapDrawable.setBounds(getBounds());
//                bitmapDrawable.setGravity(Gravity.CLIP_VERTICAL | Gravity.CLIP_HORIZONTAL);
//                bitmapDrawable.setGravity(Gravity.CENTER);
                if(mMutated)
                {
                    bitmapDrawable.mutate();
                }
                mCurrDrawable = bitmapDrawable;
                mDrawableContainerState.mSuccessed = bitmapDrawable.getConstantState();
                oldDrawable.setCallback(null);
            }
        }
        else if(image instanceof GifImage)
        {
            // 如果启动
            if (isLoadingStarted)
            {
                Drawable oldDrawable = mCurrDrawable;
                GifDrawable gifDrawable = new GifDrawable((GifImage) image);
                gifDrawable.setAlpha(mAlpha);
                gifDrawable.setVisible(isVisible(), true);
                gifDrawable.setDither(mDrawableContainerState.mDither);
                gifDrawable.setColorFilter(mColorFilter);
                gifDrawable.setState(URLDrawable.this.getState());
                gifDrawable.setLevel(getLevel());
                gifDrawable.setCallback(URLDrawable.this);
                gifDrawable.setTargetDensity(mTargetDensity);
                gifDrawable.setBounds(getBounds());
//                gifDrawable.setGravity(Gravity.CENTER);
                if(mMutated)
                {
                    gifDrawable.mutate();
                }
                mCurrDrawable = gifDrawable;
                mDrawableContainerState.mSuccessed = gifDrawable.getConstantState();
                oldDrawable.setCallback(null);
            }
        }
        mStatus = SUCCESSED;
        if (mListener != null)
        {
            mListener.onLoadSuccessed(this);
        }
        if(mFadeInImage)
        {
            mFadeInAnimationStarted = true;
        }
        
        if(image != null)
        {
            // 复制缓存路径, 新cache如果需要保存则需要
            mDrawableContainerState.mCacheFile = mCacheFile;
            sMemoryCache.put(getURL().toString(), new Pair<Drawable.ConstantState, Integer>(this.getConstantState(), getImageByteSize(image)));
        }
        // 通知重绘
        this.invalidateSelf();
    }
    
    private int getImageByteSize(Object image)
    {
        if(image instanceof Bitmap)
        {
            return Utils.getBitmapSize((Bitmap) image);
        }
        // gif无法计算大小, 只能估算. 
        else if(image instanceof GifImage)
        {
            GifImage gif = (GifImage) image;
            // 一帧bitmap所占字节数 * 2
            return gif.getWidth() * gif.getHeight() * 2
                    * ((sDefaultDrawableParms.mConfig == Bitmap.Config.ARGB_8888 ? 8 : 4));
        }
        else 
        {
            return 0;
        }
    }
    
    /**
     * 加载失败, 只能在ui线程调用
     * @param e
     */
    public void onLoadFailed(Throwable e)
    {
        Log.w(TAG, "image load failed: " + getURL() + "\n" + e.toString() , e);
//        e.printStackTrace();
//        Log.e(TAG, "test", new Exception());
        Drawable oldDrawable = mCurrDrawable;
        mCurrDrawable = mFailedDrawable;
        mCurrDrawable.setAlpha(mAlpha);
        mCurrDrawable.setVisible(isVisible(), true);
        mCurrDrawable.setDither(mDrawableContainerState.mDither);
        mCurrDrawable.setColorFilter(mColorFilter);
        mCurrDrawable.setState(URLDrawable.this.getState());
        mCurrDrawable.setLevel(getLevel());
        mCurrDrawable.setCallback(URLDrawable.this);
        mCurrDrawable.setBounds(getBounds());
        if(mMutated)
        {
            mCurrDrawable.mutate();
        }
        mCurrDrawable.setBounds(getBounds());
        oldDrawable.setCallback(null);
        mStatus = FAILED;
        
        if (mListener != null)
        {
            mListener.onLoadFialed(this, e);
        }
        if(mFadeInImage)
        {
            mFadeInAnimationStarted = true;
        }
        // 通知重绘
        this.invalidateSelf();
    }
    
    /**
     * 加载失败
     * @param e
     */
    protected void onLoadCanceled()
    {
        Log.e(TAG, "image load canceled: " + getURL());
        Drawable oldDrawable = mCurrDrawable;
        mCurrDrawable = mFailedDrawable;
        mCurrDrawable.setAlpha(mAlpha);
        mCurrDrawable.setVisible(isVisible(), true);
        mCurrDrawable.setDither(mDrawableContainerState.mDither);
        mCurrDrawable.setColorFilter(mColorFilter);
        mCurrDrawable.setState(URLDrawable.this.getState());
        mCurrDrawable.setLevel(getLevel());
        mCurrDrawable.setCallback(URLDrawable.this);
        mCurrDrawable.setBounds(getBounds());
        if(mMutated)
        {
            mCurrDrawable.mutate();
        }
        mCurrDrawable.setBounds(getBounds());
        oldDrawable.setCallback(null);
        mStatus = CANCLED;
        
        if (mListener != null)
        {
            mListener.onLoadCanceled(this);
        }
        if(mFadeInImage)
        {
            mFadeInAnimationStarted = true;
        }
        // 通知重绘
        this.invalidateSelf();
    }
    
    /**
     * 解码图片
     * @param cacheFile
     * @return
     * @throws IOException 
     */
    private Object decodeFile(File cacheFile, ProtocolDownloader downloader) throws IOException
    {
        if(cacheFile == null || !cacheFile.exists())
        {
            return null;
        }
        if(downloader != null)
        {
            Object res = downloader.decodeFile(cacheFile);
            if(res != null)
            {
                return res;
            }
        }
        // GIF动画
        if(mUseGifAnimation && GifImage.needDecodeAnimation(cacheFile))
        {
            return new GifImage(cacheFile, sDefaultDrawableParms.mTaskType);
        }
        // 非gif图片
        else
        {
//          Bitmap bitmap = BitmapFactory.decodeFile(f.getAbsolutePath(), ImageUtilities.createOptions(config));
            Options options = new Options();
            options.inPreferredConfig = sDefaultDrawableParms.mConfig;
            options.inDensity = DisplayMetrics.DENSITY_DEFAULT;
            options.inTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
            options.inScreenDensity = DisplayMetrics.DENSITY_DEFAULT;
            options.inJustDecodeBounds = true;
            
            // decode出图片大小
            BitmapFactory.decodeFile(cacheFile.getAbsolutePath(), options);
            // 计算samplesize
            options.inSampleSize = calculateInSampleSize(options, mReqWidth, mReqHeight);
            
            // 重新decode
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeFile(cacheFile.getAbsolutePath(), options);
        }
    }
    
    private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
    {
        if(reqWidth == 0 || reqHeight == 0 || reqWidth == -1 || reqHeight == -1)
        {
            return 1;
        }
        // Raw height and width of image
        int height = options.outHeight;
        int width = options.outWidth;
        int inSampleSize = 1;
        
        // 超过1.5倍会被缩放
        while (height > reqHeight || width > reqWidth)
        {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            
            int ratio = heightRatio > widthRatio ? heightRatio : widthRatio;
            if (ratio >= 2)
            {
                width /= 2;
                height /= 2;
                inSampleSize *= 2;
            }
            else
            {
                break;
            }
        }

//        if (height > reqHeight || width > reqWidth)
//        {
//            
////            if (width > height)
////            {
////                inSampleSize = Math.round((float) height / (float) reqHeight);
////            }
////            else
////            {
////                inSampleSize = Math.round((float) width / (float) reqWidth);
////            }
//            inSampleSize = Math.round(Math.max((float) height / (float) reqHeight, (float) width / (float) reqWidth));
//        }
        return inSampleSize;
    }

    /**
     * 生成缓存文件名
     * @return
     */
    private String hashKeyForDisk()
    {
        return CACHE_PREFIX + Utils.Crc64String(getURL().toString());
    }

    /**
     * 初始化, 需要在首次使用之前调用
     * 
     * @param params 参数
     */
    public static void init(URLDrawableParams params)
    {
        if (sDefaultDrawableParms == null)
        {
            URLDrawable.sDefaultDrawableParms = params;
            if(params.mMemoryCache == null)
            {
                sMemoryCache = new MemoryCache(params.mMemoryCacheSize);
            }
            else
            {
                sMemoryCache = params.mMemoryCache;
            }
            DiskLruInitThread initThread = new DiskLruInitThread();
            initThread.setName("DiskLruCache init");
            initThread.start();
        }
        else
        {
            throw new IllegalArgumentException("please don't call setURLDrawableParams twice");
        }
    }

    private static class DiskLruInitThread extends Thread
    {
        @Override
        public void run()
        {
            URLDrawable.initDiskCache();
        }
    }
    
    /**
     * 检查
     */
    private static void checkParams()
    {
        if (sDefaultDrawableParms == null)
        {
            throw new IllegalStateException("Default params is not seted, please call setURLDrawableParams first");
        }
    }

    
    
    public interface URLDrawableListener
    {
        /**
         * 加载成功
         *
         * @param drawable 加载成功的图片
         */
        void onLoadSuccessed(URLDrawable drawable);

        /**
         * 加载失败
         *
         * @param drawable 加载失败的图片
         * @param cause 失败的原因
         */
        void onLoadFialed(URLDrawable drawable, Throwable cause);
        
        /**
         * 取消加载
         * @param drawable
         */
        void onLoadCanceled(URLDrawable drawable);
    }
    
    /**
     * 保存实际状态
     * 
     *
     */
    final static class URLState extends ConstantState {

        public int mChangingConfigurations;
        private URL mUrl;

        // 成功的图片
        private ConstantState mSuccessed;
        private boolean mDither = true;
        private File mCacheFile;

        URLState(URL mUrl)
        {
            super();
            this.mUrl = mUrl;
        }

        @Override
        public int getChangingConfigurations()
        {
            return mChangingConfigurations;
        }

        public boolean canConstantState()
        {
            return true;
        }

        public int getOpacity()
        {
            return PixelFormat.TRANSPARENT;
        }

        public boolean isStateful()
        {
            return true;
        }

        @Override
        public Drawable newDrawable()
        {
            return new URLDrawable(this, null);
        }

        @Override
        public Drawable newDrawable(Resources res)
        {
            return new URLDrawable(this, res);
        }
    }
    
    private URLDrawable(URL url, Drawable loading, Drawable failed)
    {
        this.mDrawableContainerState = new URLState(url);
        this.mLoadingDrawable = loading;
        this.mFailedDrawable = failed;
        this.mCurrDrawable = mLoadingDrawable;
    }
    
//    private URLDrawable(Resources res, URL url, ConstantState loading, ConstantState failed)
//    {
//        this.mDrawableContainerState = new URLState(url);
//        this.mLoadingDrawable = loading.newDrawable(res);
//        this.mFailedDrawable = failed.newDrawable(res);
//        this.mCurrDrawable = mLoadingDrawable;
////        this.mDrawableContainerState.density = res.getDisplayMetrics().densityDpi;        
//    }
    
    private URLDrawable(URLState state, Resources res)
    {
        this.mDrawableContainerState = state;
        // 加载完成, 生成副本
        if(state.mSuccessed != null)
        {
            this.mCurrDrawable = mDrawableContainerState.mSuccessed.newDrawable(res);
            isLoadingStarted = true;
            mCacheFile = state.mCacheFile;
            mStatus = SUCCESSED;
//            isLoadingFinished = true;
        }
        // 否则, 生成一个新的
        else
        {
            this.mCurrDrawable = sDefaultDrawableParms.mLoadingDrawable.newDrawable(res);
            mCacheFile = state.mCacheFile;
            isLoadingStarted = false;
//            isLoadingFinished = false;
        }
        this.mCurrDrawable.setCallback(this);
    }

    /**
     * 加载完成后, 是否以渐现的方式显示图片
     * @param mFadeInImage
     */
    public void setFadeInImage(boolean mFadeInImage)
    {
        this.mFadeInImage = mFadeInImage;
    }
    
    /**
     * 是否播放gif.
     * 有bug, 如果是从内存获取的.则这个值无效
     * @param mUseGifAnimation
     */
    public void setUseGifAnimation(boolean mUseGifAnimation)
    {
        this.mUseGifAnimation = mUseGifAnimation;
    }
    
    /**
     * 设置Headers..
     * @param mHeaders
     */
    public void setHeaders(Header... mHeaders)
    {
        this.mHeaders = mHeaders;
    }
    
    /**
     * 添加Header
     * @param name
     * @param value
     */
    public void addHeader(String name, String value)
    {
        if(mHeaders == null || mHeaders.length == 0)
        {
            mHeaders = new Header[] { new BasicHeader(name, value) };
        }
        else
        {
            Header[] newHeaders = new Header[mHeaders.length + 1];
            System.arraycopy(mHeaders, 0, newHeaders, 0, mHeaders.length);
            newHeaders[mHeaders.length] = new BasicHeader(name, value);
            mHeaders = newHeaders;
        }
    }
    
    /**
     * 设置Cookies
     * @param mCookies
     */
    public void setCookies(CookieStore mCookies)
    {
        this.mCookies = mCookies;
    }
    
    /**
     * 添加一段cookie
     * @param name
     * @param value
     */
    public void addCookies(String name, String value)
    {
        if(mCookies == null)
        {
            mCookies = new BasicCookieStore();
        }
        mCookies.addCookie(new BasicClientCookie(name, value));
    }
    
    /**
     * 设置缓存文件路径
     * @param mCacheFile
     */
    public void setCacheFile(File mCacheFile)
    {
        this.mCacheFile = mCacheFile;
    }
    
    /**
     * 获取缓存文件路径
     * @return
     */
    public File getCacheFile()
    {
        return mCacheFile;
    }
    
    /**
     * 添加监听器
     *
     * @param listener
     */
    public void setURLDrawableListener(URLDrawableListener listener)
    {
        this.mListener = listener;
    }
    
    /**
     * 获取tag
     * @return
     */
    public Object getTag()
    {
        return mTag;
    }

    /**
     * 设置tag
     * @param tag
     */
    public void setTag(Object tag)
    {
        this.mTag = tag;
    }

    /**
     * 初始化DiskCache.
     */
    public static void initDiskCache() {
        // Set up disk cache
        synchronized (sDiskCacheLock) {
            if (sDiskCache == null || sDiskCache.isClosed()) {
                File diskCacheDir = sDefaultDrawableParms.mDiskCachePath;
                if (diskCacheDir != null) {
                    if (!diskCacheDir.exists()) {
                        diskCacheDir.mkdirs();
                    }
//                    if (Utils.getUsableSpace(diskCacheDir) > sDefaultDrawableParms.mDiskCacheSize)
                    // 这一步由外层判断
                    {
                        try {
                            sDiskCache = DiskLruCache.open(
                                    diskCacheDir, 1, 1, sDefaultDrawableParms.mDiskCacheSize);
//                            if (BuildConfig.DEBUG) {
//                                Log.d(TAG, "Disk cache initialized");
//                            }
                        } catch (final IOException e) {
                            // 不使用文件缓存
                            sDefaultDrawableParms.mDiskCachePath = null;
                            Log.e(TAG, "initDiskCache - " + e);
                        }
                    }
                }
            }
            sDiskCacheStarting = false;
            sDiskCacheLock.notifyAll();
        }
    }
    
    /**
     * 从文件缓存里读取
     * @param downloader 
     *
     * @param url 文件rul
     * @return Bitmap或者gif, 取决于文件类型
     * @throws IOException 
     */
    private Object getImageFromDiskLruCache(String key, ProtocolDownloader downloader) throws IOException 
    {
//        final String key = hashKeyForDisk();
        // 还没初始化完毕
        synchronized (sDiskCacheLock)
        {
            // 等待
            while (sDiskCacheStarting)
            {
                try
                {
                    sDiskCacheLock.wait();
                }
                catch (InterruptedException e)
                {
                }
            }
            if (sDiskCache != null)
            {
                // 获取snapshot
                final DiskLruCache.Snapshot snapshot = sDiskCache.get(key);
                if (snapshot != null && !downloader.isDirty(getURL(), snapshot.getFile(DISK_CACHE_INDEX).lastModified()))
                {
//                    File f = snapshot.getFile(DISK_CACHE_INDEX);
                    return decodeFile(snapshot.getFile(DISK_CACHE_INDEX), downloader);
                }
            }
            return null;
        }
    }
    
    /**
     * 将文件下载到lruDiskCache缓存中
     * @param url
     * @param result
     * @param cacheKey
     * @param downloader 
     * @return
     * @throws IOException
     */
    private Object downloadImageToDiskLruCache(URL url, final String cacheKey, ProtocolDownloader downloader)
            throws IOException
    {
        Object result = null;
        File f = null;
        // 获取downloader
//        ProtocolDownloader downloader = sDefaultDrawableParms.mDownLoaderMap.get(url.getProtocol());
        if(downloader != null)
        {
            // 使用disk cache
            if(downloader.useDiskCache())
            {
                OutputStream out = null;
                // TODO 这里存在bug, 如果同一时刻同时download同一个url, 则第二个editor会返回null
                // 导致第二张图是红x
                // 可以考虑如果editor为null, 则wait线程
                final DiskLruCache.Editor editor = sDiskCache.edit(cacheKey);
                // 写入diskcache..
                try
                {
                    if (editor != null) 
                    {
                        out = editor.newOutputStream(DISK_CACHE_INDEX);
                        f = downloader.downloadImage(url, out, mHeaders, mCookies);
                        editor.commit();
                    }
                }
                finally
                {
                    try
                    {
                        if (out != null)
                        {
                            out.close();
                        }
                    }
                    catch (IOException e){}
                }
                // 写入文件成功, 重新获取一次
                if (f == null)
                {
                    result = getImageFromDiskLruCache(cacheKey, downloader);
                }
                // 如果保存位置发生了改变(不推荐这样做), 则decode新的文件
                else
                {
                    result = decodeFile(f, downloader);
                }
            }
            else
            {
                result = decodeFile(downloader.downloadImage(url, null, mHeaders, mCookies), downloader);
            }
        }
        return result;
    }
    
//    /**
//     * 销毁drawable
//     */
//    void destory()
//    {
//        for (int i = 0; i < sPendingActions.size(); i++)
//        {
//            if(sPendingActions.get(i).get() == this)
//            {
//                sPendingActions.remove(i);
//                return;
//            }
//        }
//    }
    
    /**
     * 获取URLDrawable
     * @param url
     * @return
     */
    public static URLDrawable getDrawable(URL url)
    {
        return getDrawable(url, null, null);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(URL url, int reqWidth, int reqHeight)
    {
        return getDrawable(url, reqWidth, reqHeight, null, null);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(URL url, Drawable loading, Drawable failed)
    {
        return getDrawable(url, 0, 0, loading, failed);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(URL url, int reqWidth, int reqHeight, Drawable loading,
            Drawable failed)
    {
        return getDrawable(null, url, reqWidth, reqHeight, loading, failed);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(Resources res, URL url)
    {
        return getDrawable(res, url, null, null);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(Resources res, URL url, int reqWidth, int reqHeight)
    {
        return getDrawable(res, url, reqWidth, reqHeight, null, null);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(Resources res, URL url, Drawable loading, Drawable failed)
    {
        return getDrawable(res, url, 0, 0, loading, failed);
    }
    
    /**
     * 获取URLDrawable
     * @param res resources对象
     * @param url 图片的url 
     * @param reqWidth sampleSizeWidth
     * @param reqHeight sampleSizeheight
     * @param loading loading的图片
     * @param failed 失败的图片
     * @return URLDrawable
     */
    public static URLDrawable getDrawable(Resources res, URL url, int reqWidth, int reqHeight, Drawable loading,
            Drawable failed)
    {
        checkParams();
        // 1. 从内存读取
        
        Pair<ConstantState, Integer> cache = sMemoryCache.get(url.toString());
        if(cache != null)
        {
            return autoScale(res, (URLDrawable) cache.first.newDrawable(res));
        }
        
        URLDrawable d = new URLDrawable(url,
                loading == null ? sDefaultDrawableParms.mLoadingDrawable.newDrawable(null) : loading,
                failed == null ? sDefaultDrawableParms.mFailedDrawable.newDrawable(null) : failed);
        d.mUseGifAnimation = sDefaultDrawableParms.mUseGifAnimation;
        d.mFadeInImage = sDefaultDrawableParms.mFadeInImage;
        if(reqWidth == 0 || reqHeight == 0)
        {
            d.mReqWidth = sDefaultDrawableParms.mReqWidth;
            d.mReqHeight = sDefaultDrawableParms.mReqHeight;
        }
        else
        {
            d.mReqWidth = reqWidth;
            d.mReqHeight = reqHeight;
        }
        return autoScale(res, d);
    }

    private static URLDrawable autoScale(Resources res, URLDrawable d)
    {
        // 如果启用自动缩放...
        if(sDefaultDrawableParms.mAutoScaleByDensity)
        {
            if(res != null)
            {
                d.setTargetDensity(res.getDisplayMetrics().densityDpi);
            }
            else
            {
                d.setTargetDensity(sDefaultDrawableParms.mDeviceDensity);
            }
        }
        return d;
    }

    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(String url) throws IllegalArgumentException
    {
        return getDrawable(url, null, null);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(String url, int reqWidth, int reqHeight) throws IllegalArgumentException
    {
        return getDrawable(url, reqWidth, reqHeight, null, null);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(String url, Drawable loading, Drawable failed) throws IllegalArgumentException
    {
        return getDrawable(url, 0, 0, loading, failed);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(String url, int reqWidth, int reqHeight, Drawable loading, Drawable failed) throws IllegalArgumentException
    {
        return getDrawable(null, url, reqWidth, reqHeight, loading, failed);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(Resources res, String url) throws IllegalArgumentException
    {
        return getDrawable(res, url, null, null);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(Resources res, String url, int reqWidth, int reqHeight) throws IllegalArgumentException
    {
        return getDrawable(res, url, reqWidth, reqHeight, null, null);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(Resources res, String url, Drawable loading, Drawable failed) throws IllegalArgumentException
    {
        return getDrawable(res, url, 0, 0, loading, failed);
    }
    
    /**
     * 获取URLDrawable
     * @return
     */
    public static URLDrawable getDrawable(Resources res, String url, int reqWidth, int reqHeight, Drawable loading, Drawable failed) throws IllegalArgumentException
    {
        try
        {
            URL u = new URL(url);
            return getDrawable(res, u, reqWidth, reqHeight, loading, failed);
        }
        catch (MalformedURLException e)
        {
            throw new IllegalArgumentException("illegal url format: " + url);
        }
    }
    
    /**
     * 图片另存为.不要在ui线程调用
     * 仅当文件下载完成后才能成功
     * 如果文件名没有后缀, 则会自动添加后缀
     * @param target 目标文件
     * @return 保存的文件, 不为空则说明下载完成. 
     * @throws IOException 当写文件出现异常
     */
    public String saveTo(String target) throws IOException
    {
        if(getStatus() != SUCCESSED || sDiskCacheStarting || sDiskCache == null)
        {
            return null;
        }
        else
        {
            File cache = mCacheFile;
            
            if(cache == null)
            {
                String cacheKey = hashKeyForDisk();
                final DiskLruCache.Snapshot snapshot = sDiskCache.get(cacheKey);
                if(snapshot != null)
                {
                    cache = snapshot.getFile(DISK_CACHE_INDEX);
                }
            }
            
            // 复制文件
            if(cache != null)
            {
                // 没有设置后缀的话, 动态添加一个
                if(target.indexOf(".") == -1)
                {   
                   String suffix = mCurrDrawable instanceof GifDrawable ? ".gif" : ".jpg";
                   target = target + suffix;
                }
                
                Utils.copyFile(cache, new File(target));
            }
            return cache != null ? target : null;
            
        }
    }
    
    /**
     * 暂停加载, 在滚动时调用, 可以提高滚动性能
     */
    public static void pause()
    {
        synchronized (sPauseLock)
        {
            sPause = true;
            GifImage.pauseAll();
        }
    }
    
    /**
     * 恢复暂停, 需要在ui线程调用
     */
    public static void resume()
    {
        synchronized (sPauseLock)
        {
            sPause = false;
            sPauseLock.notifyAll();
            // 逆序迭代
            for (int i = sPendingActions.size() - 1; i >= 0; i--)
            {
                URLDrawable drawable = sPendingActions.get(i).get();
                if(drawable != null)
                {
                    // 通过unScheduleSelf通知. 如果图片所在的view已经不存在了. 则不会通知
                    drawable.scheduleSelf(drawable, SystemClock.uptimeMillis() + 1);
                }
            }
            sPendingActions.clear();
            GifImage.resumeAll();
        }
    }
}